package com.security6.smssecurity.config;

import com.security6.smssecurity.filter.ImageCodeFilter;
import com.security6.smssecurity.service.impl.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.UserDetailsManagerConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * @Author: wangzhen
 * @Date: 2024-08-16 12:07
 * @Version: v1.0.0
 * @Description: security 主配置
 **/
@Configuration
public class WebSecurityConfig {

    @Autowired
    @Qualifier("myUserService")
    private UserService userService;

    @Autowired
    private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;

    /**
     * 密码验证器
     */
    @Autowired
    private PassWordEncorder passWordEncorder;

    /**
     * 成功处理器
     */
    @Autowired
    private AuthenctiationSuccessHandler authenctiationSuccessHandler;

    /**
     * 失败处理器
     */
    @Autowired
    private AuthenctiationFailHandler authenctiationFailHandler;

    /**
     * 失败处理器
     */
    @Autowired
    private ImageCodeFilter imageCodeFilter;

    @Autowired
    private DataSource dataSource;


    /**
     * 向Security注入用户信息
     */
    //@Override
    //protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //    auth.userDetailsService(userService).passwordEncoder(passWordEncorder);
    //}

/*    @Bean
    UserDetailsService userDetailsService() {
        UserDetails userDetails = User.withUsername("admin")
                .password("{noop}password")
                .authorities("ADMIN")
                .roles("headmaster")
                .build();
        return new InMemoryUserDetailsManager(userDetails);
    }*/

    // 在这里比较的 org.springframework.security.authentication.dao.DaoAuthenticationProvider
    // DaoAuthenticationProvider是在这里被注入的 InitializeUserDetailsBeanManagerConfigurer
    // 会拿容器中的 密码器
    @Bean
    PasswordEncoder passwordEncoder() {
        //return PasswordEncoderFactories.createDelegatingPasswordEncoder();
        return org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance();
    }

    /**
     * 配置规则
     */
    @Bean
    public SecurityFilterChain configure(HttpSecurity http) throws Exception {

        //添加自定义过滤器 来验证图形验证码 这个过滤器肯定是在验证用户名账号 密码之前执行的
        //开启登陆配置
        http
                .authorizeHttpRequests(request->{
                    request.requestMatchers("/code/**","/no-login").permitAll()
                            .requestMatchers("/no-authorize").authenticated()
                            .requestMatchers("/need-authorize").hasRole("headmaster")
                            .anyRequest().authenticated();
                })
                .csrf(csrf->csrf.disable())
                .userDetailsService(userService)
                //.authenticationProvider(new DaoAuthenticationProvider(passwordEncoder()))
                .formLogin(form->{
                    form
                            .loginPage("/login_page")
                            .loginProcessingUrl("/login").permitAll()
                            .usernameParameter("username")
                            .passwordParameter("password")
                            .successHandler(authenctiationSuccessHandler)
                            .failureHandler(authenctiationFailHandler)
                            ;
                })
                .rememberMe(remeber->{
                    remeber.userDetailsService(userService).tokenRepository(tokenRepository()).tokenValiditySeconds(3600);
                })
                .logout(Customizer.withDefaults())
                .exceptionHandling(execption->execption.accessDeniedHandler(getAccessDeniedHandler()))
                .addFilterBefore(imageCodeFilter, UsernamePasswordAuthenticationFilter.class)
                .with(smsCodeAuthenticationSecurityConfig, Customizer.withDefaults())
        ;

    return http.build();

                //.apply(smsCodeAuthenticationSecurityConfig)
                //.addFilterBefore(imageCodeFilter, UsernamePasswordAuthenticationFilter.class).authorizeRequests()
                //.antMatchers("/code/**").permitAll()
                //// 登录之后就能访问
                //.antMatchers("/no-authorize").authenticated()
                //// 表示访问/admin/** 需要校长角色权限
                //.antMatchers("/need-authorize").hasRole("校长")
                //// 其他的路径都是登录后即可访问
                //.anyRequest().authenticated()
                //.and().formLogin()
                //// 定义登录页面，未登录时，访问一个需要登录之后才能访问的接口，会自动跳转到该页面
                //.loginPage("/login_page")
                ////登录成功的处理器
                //.successHandler(authenctiationSuccessHandler)
                ////登录失败的处理器
                //.failureHandler(authenctiationFailHandler)
                //// 登录处理接口
                //.loginProcessingUrl("/login")
                //// 定义登录时，用户名的 key，默认为 username
                //.usernameParameter("username")
                ////定义登录时，用户密码的 key，默认为 password
                //.passwordParameter("password").permitAll()
                //.and()
                //.rememberMe()
                //.tokenRepository(tokenRepository())
                ////过期时间为1小时
                //.tokenValiditySeconds(3600)
                //.and()
                //.logout()
                //////和表单登录相关的接口统统都直接通过
                //.permitAll()
                //.and().csrf().disable().exceptionHandling().accessDeniedHandler(getAccessDeniedHandler());
    }


    @Bean
    public PersistentTokenRepository tokenRepository() {
        //JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        //tokenRepository.setDataSource(dataSource);
        //tokenRepository.setCreateTableOnStartup(true);
        InMemoryTokenRepositoryImpl inMemoryTokenRepository = new InMemoryTokenRepositoryImpl();
        return inMemoryTokenRepository;
    }

    /**
     * 对于/static/ 和 index.html 下的路径都不用认证
     */
    //@Override
    //public void configure(WebSecurity web) throws Exception {
    //    web.ignoring().antMatchers("/no-login","/code/**");
    //}

    /**
     * 用户未认证异常拦截
     */
    @Bean
    AccessDeniedHandler getAccessDeniedHandler() {
        return new AuthenticationAccessDeniedHandler();
    }
}